Skip to content

Feat(Client): 카테고리 수정 팝업 checkbox 추가 및 api 연결#279

Open
jjangminii wants to merge 15 commits intodevelopfrom
feat/#269/modal-checkbox-add
Open

Feat(Client): 카테고리 수정 팝업 checkbox 추가 및 api 연결#279
jjangminii wants to merge 15 commits intodevelopfrom
feat/#269/modal-checkbox-add

Conversation

@jjangminii
Copy link
Collaborator

@jjangminii jjangminii commented Feb 25, 2026

📌 Related Issues

관련된 Issue를 태그해주세요. (e.g. - close #25)

📄 Tasks

  • 카테고리 수정 팝업 checkbox 추가
  • api 연결
  • 체크박스 xsmall 사이즈 추가했습니다-!

⭐ PR Point (To Reviewer)

  • 진짜.. 롤백을 몇번했는데 체크박스가 api 연결은 되는데 수정 팝업 불러올때 반영되어서 안들어오네요..

📷 Screenshot

image

Summary by CodeRabbit

  • New Features
    • 카테고리 생성 및 편집 시 공개 여부(isPublic) 설정 추가
    • 편집/생성 팝업에 "같은 관심 직무 사용자들에게 공유하기" 체크박스 추가(기본값 동기화 및 편집 시 상태 전달)
    • 팝업이 체크박스 옵션을 받아 렌더링하도록 확장
    • 체크박스에 초소형(xsmall) 크기 옵션 추가
    • 카테고리 상세 정보 조회 및 편집 시 원격 데이터를 불러오는 개선된 편집 흐름 추가

@jjangminii jjangminii self-assigned this Feb 25, 2026
@jjangminii jjangminii linked an issue Feb 25, 2026 that may be closed by this pull request
@vercel
Copy link

vercel bot commented Feb 25, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
pinback-client-client Ready Ready Preview, Comment Feb 27, 2026 7:22am
pinback-client-landing Ready Ready Preview, Comment Feb 27, 2026 7:22am

@github-actions github-actions bot added the feat 기능 개발하라 개발 달려라 달려 label Feb 25, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 25, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

카테고리 생성/수정 흐름에 isPublic/shareToJobUsers 플래그를 추가하고 API 경로를 v1→v3로 변경하며 PUT→PATCH로 전환했습니다. Popup에 체크박스 옵션을 도입하고 사이드바, 훅, 타입, 익스텐션 훅 등 전반에 isPublic 상태와 시그니처를 전파했습니다.

Changes

Cohort / File(s) Summary
API / 쿼리 레이어
apps/client/src/shared/apis/axios.ts, apps/client/src/shared/apis/queries.ts, apps/extension/src/apis/axios.ts
postCategory/postCategoriesisPublic 인자 추가 및 엔드포인트 v1→v3 변경. putCategorypatchCategory(PUT→PATCH)로 이름·시그니처 변경. 쿼리 훅 usePutCategoryusePatchCategory로 갱신. extension 요청 타입에 isPublic 추가(중복 선언 주의).
사이드바 UI 및 팝업 포털
apps/client/src/shared/components/sidebar/PopupPortal.tsx, apps/client/src/shared/components/sidebar/Sidebar.tsx, apps/client/src/shared/components/sidebar/OptionsMenuPortal.tsx
생성/편집 플로우에 shareToJobUsers/isPublic 상태 추가. PopupPortal 콜백 시그니처 확장(onCreateConfirm, onEditConfirm). OptionsMenuPortal에 getCategory 도입 및 onEditisPublic 전달. Popup key 핸들링 변경.
훅 및 액션
apps/client/src/shared/components/sidebar/hooks/useCategoryActions.ts, apps/client/src/shared/hooks/useCategoryPopups.ts, apps/extension/src/hooks/useCategoryManager.ts
handleCreateCategory/handlePatchCategory 시그니처에 isPublic 추가. openEdit 및 popup 상태 타입에 isPublic 확장. usePutCategoryusePatchCategory로 대체. extension 훅에 isPublic, setIsPublic 추가 및 반환.
타입 변경
apps/client/src/shared/types/api.ts
Category 타입에 isPublic: boolean 필드 추가 및 CategoryDetailResponse 인터페이스 추가.
디자인 시스템 — Popup / Checkbox
packages/design-system/src/components/popup/Popup.tsx, packages/design-system/src/components/popup/PopupContainer.tsx, packages/design-system/src/components/checkbox/Checkbox.tsx
PopupPopupCheckboxOption 인터페이스 및 checkboxOption? prop 추가해 조건부 체크박스 렌더링 지원. Checkbox'xsmall' size 옵션 추가.

Sequence Diagram(s)

sequenceDiagram
    participant User as 사용자
    participant UI as PopupPortal (클라이언트)
    participant Popup as Popup (디자인시스템)
    participant Hook as useCategoryActions / useCategoryManager
    participant API as Axios (/api/v3/categories)

    User->>UI: 생성/수정 요청(열기)
    UI->>Popup: checkboxOption 전달 (isPublic / shareToJobUsers)
    Popup->>User: 입력 UI + 체크박스 표시
    User->>Popup: 이름 입력 + 체크박스 선택
    Popup->>UI: onCreateConfirm(name, shareToJobUsers) / onEditConfirm(id, name, isPublic)
    UI->>Hook: handleCreateCategory(name, isPublic) / handlePatchCategory(id, name, isPublic)
    Hook->>API: postCategory(name, isPublic) / patchCategory(id, name, isPublic)
    API-->>Hook: 응답
    Hook->>UI: 캐시 무효화 및 상태 업데이트
    UI-->>User: 팝업 닫기 및 UI 갱신
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested labels

🛠️ Feature, frontend, api

Suggested reviewers

  • constantly-dev
  • jllee000

Poem

🐰 팝업에 체크 한 칸 깜짝 웃고,
v1은 떠나고 v3가 반갑게 인사하네.
PUT은 PATCH로 살며시 바뀌어,
isPublic 손에 쥐고 함께 달려,
카테고리들 새빛을 맞이하네. ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (1 warning, 2 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Linked Issues check ❓ Inconclusive PR은 issue #269와 관련하여 모달 체크박스 추가 및 API 연결 작업을 수행했으나, issue #25는 progress bar 구현으로 본 PR의 범위와 무관합니다. issue #25는 본 PR과 무관하므로 제외하고, #269와의 관련성을 명확히 하기 위해 추가 검증이 필요합니다.
Out of Scope Changes check ❓ Inconclusive PR에서 카테고리 checkbox 기능, API 연결, checkbox xsmall 사이즈 추가 등 일관된 범위 내의 변경을 수행했으나, 저자가 수정 팝업 로드 시 변경사항 미반영 이슈를 보고했습니다. 보고된 기술 이슈(수정 팝업 미반영)가 해결되었는지 확인 필요하며, 서버 수정 반영 후 재검증이 필요합니다.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed 제목이 PR의 주요 변경 사항인 카테고리 수정 팝업 checkbox 추가 및 API 연결을 명확하게 설명하고 있습니다.
Description check ✅ Passed PR 설명이 필수 템플릿 섹션(Related Issues, Tasks, PR Point)을 모두 포함하고 있으며, 구현 내용과 이슈 사항을 구체적으로 기술했습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/#269/modal-checkbox-add

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Feb 25, 2026

✅ Storybook chromatic 배포 확인:
🐿️ storybook

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/client/src/shared/components/sidebar/PopupPortal.tsx`:
- Around line 44-50: The effect in PopupPortal (useEffect watching popup)
unconditionally calls setShareToJobUsers(false), which resets the checkbox for
edit flows and overwrites existing visibility; change the logic in the effect to
initialize shareToJobUsers based on popup when popup.kind === 'edit' (e.g., read
the existing visibility flag from popup or popup.shareToJobUsers) and only
default to false for create flows, updating the setShareToJobUsers call in the
useEffect that references popup so edit restores the current value and create
sets false; ensure any other places that set shareToJobUsers on open (calls
around lines where shareToJobUsers/setShareToJobUsers are used, and the confirm
handler that passes the value at line ~95) are consistent with this
initialization.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a1ee533 and 3bf8c23.

📒 Files selected for processing (7)
  • apps/client/src/shared/apis/axios.ts
  • apps/client/src/shared/apis/queries.ts
  • apps/client/src/shared/components/sidebar/PopupPortal.tsx
  • apps/client/src/shared/components/sidebar/Sidebar.tsx
  • apps/client/src/shared/components/sidebar/hooks/useCategoryActions.ts
  • packages/design-system/src/components/checkbox/Checkbox.tsx
  • packages/design-system/src/components/popup/Popup.tsx

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
apps/client/src/shared/components/sidebar/PopupPortal.tsx (1)

44-44: ⚠️ Potential issue | 🟡 Minor

생성 팝업 첫 렌더에서 체크박스 기본값이 잠깐 잘못 보일 수 있습니다.

초기값이 true라서 create 오픈 시 이펙트 반영 전 한 프레임 동안 체크된 상태로 보일 수 있습니다. 기본값을 false로 두는 편이 안전합니다.

수정 제안 diff
-  const [shareToJobUsers, setShareToJobUsers] = useState(true);
+  const [shareToJobUsers, setShareToJobUsers] = useState(false);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/client/src/shared/components/sidebar/PopupPortal.tsx` at line 44, The
checkbox initial state shareToJobUsers is set to true causing a flash of checked
state on first render; change the useState initialization in PopupPortal
(shareToJobUsers, setShareToJobUsers) to start as false and ensure any useEffect
or logic that updates shareToJobUsers on open still sets the correct value after
the popup opens so the intended default is applied without a visual flash.
🧹 Nitpick comments (1)
apps/client/src/shared/components/sidebar/PopupPortal.tsx (1)

128-136: checkboxOption 객체 중복을 상수로 추출해 주세요.

create/edit 양쪽에 동일 블록이 반복되어 있어 이후 문구/동작 변경 시 누락 가능성이 있습니다.

리팩터 제안 diff
   const showCheckbox = popup.kind === 'create' || popup.kind === 'edit';
+  const checkboxOption = showCheckbox
+    ? {
+        label: '같은 관심 직무 사용자들에게 공유하기',
+        isSelected: shareToJobUsers,
+        onSelectedChange: setShareToJobUsers,
+      }
+    : undefined;

@@
-            checkboxOption={
-              showCheckbox
-                ? {
-                    label: '같은 관심 직무 사용자들에게 공유하기',
-                    isSelected: shareToJobUsers,
-                    onSelectedChange: setShareToJobUsers,
-                  }
-                : undefined
-            }
+            checkboxOption={checkboxOption}
@@
-            checkboxOption={
-              showCheckbox
-                ? {
-                    label: '같은 관심 직무 사용자들에게 공유하기',
-                    isSelected: shareToJobUsers,
-                    onSelectedChange: setShareToJobUsers,
-                  }
-                : undefined
-            }
+            checkboxOption={checkboxOption}

Also applies to: 152-160

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/client/src/shared/components/sidebar/PopupPortal.tsx` around lines 128 -
136, Extract the repeated checkboxOption object into a single constant and reuse
it in both create and edit usages to avoid duplication; specifically, create a
const (e.g., sharedCheckboxOption) built from showCheckbox, shareToJobUsers, and
setShareToJobUsers with label '같은 관심 직무 사용자들에게 공유하기' and then pass
sharedCheckboxOption where checkboxOption is currently constructed in
PopupPortal (the blocks around checkboxOption at lines shown and the similar
block at 152-160). Ensure the constant preserves the conditional behavior
(undefined when showCheckbox is false).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@apps/client/src/shared/components/sidebar/PopupPortal.tsx`:
- Line 44: The checkbox initial state shareToJobUsers is set to true causing a
flash of checked state on first render; change the useState initialization in
PopupPortal (shareToJobUsers, setShareToJobUsers) to start as false and ensure
any useEffect or logic that updates shareToJobUsers on open still sets the
correct value after the popup opens so the intended default is applied without a
visual flash.

---

Nitpick comments:
In `@apps/client/src/shared/components/sidebar/PopupPortal.tsx`:
- Around line 128-136: Extract the repeated checkboxOption object into a single
constant and reuse it in both create and edit usages to avoid duplication;
specifically, create a const (e.g., sharedCheckboxOption) built from
showCheckbox, shareToJobUsers, and setShareToJobUsers with label '같은 관심 직무
사용자들에게 공유하기' and then pass sharedCheckboxOption where checkboxOption is
currently constructed in PopupPortal (the blocks around checkboxOption at lines
shown and the similar block at 152-160). Ensure the constant preserves the
conditional behavior (undefined when showCheckbox is false).

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3bf8c23 and 41db846.

📒 Files selected for processing (5)
  • apps/client/src/shared/components/sidebar/OptionsMenuPortal.tsx
  • apps/client/src/shared/components/sidebar/PopupPortal.tsx
  • apps/client/src/shared/components/sidebar/Sidebar.tsx
  • apps/client/src/shared/hooks/useCategoryPopups.ts
  • apps/client/src/shared/types/api.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/client/src/shared/components/sidebar/Sidebar.tsx

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
apps/client/src/shared/components/sidebar/Sidebar.tsx (2)

121-121: find 콜백에서 변수 섀도잉이 발생합니다.

외부 변수 cfind 콜백 파라미터 c가 동일한 이름을 사용하여 가독성이 저하됩니다.

♻️ 변수명 변경 제안
 const getCategory = (id: number | null) => {
-  const c = categories?.categories.find((c) => c.id === id) ?? null;
-  if (!c) return null;
-  return { id: c.id, name: c.name, isPublic: (c as any).isPublic ?? true };
+  const category = categories?.categories.find((cat) => cat.id === id) ?? null;
+  if (!category) return null;
+  return { id: category.id, name: category.name, isPublic: (category as any).isPublic ?? true };
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/client/src/shared/components/sidebar/Sidebar.tsx` at line 121, The code
shadows the outer variable c in the expression categories?.categories.find((c)
=> c.id === id) ?? null;—rename the find callback parameter to a distinct name
(e.g., category or cat) to avoid shadowing and improve readability; update the
expression to use categories?.categories.find((category) => category.id === id)
?? null so the outer variable and callback param are unambiguous (referencing
the find call on categories.categories in Sidebar.tsx).

207-210: isPublic ?? true 기본값이 getCategory 내부 기본값과 중복됩니다.

getCategory 함수에서 이미 isPublic ?? true를 반환하므로, 여기서 isPublic ?? true는 중복입니다. getCategorynull을 반환하면 이 콜백은 호출되지 않으므로 isPublic은 항상 정의되어 있습니다.

♻️ 중복 기본값 제거
-            onEdit={(id, name, isPublic) =>
-              openEdit(id, name, isPublic ?? true)
-            }
+            onEdit={(id, name, isPublic) => openEdit(id, name, isPublic!)}

또는 openEditisPublic 파라미터가 optional이라면 그냥 전달해도 됩니다:

onEdit={(id, name, isPublic) => openEdit(id, name, isPublic)}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/client/src/shared/components/sidebar/Sidebar.tsx` around lines 207 -
210, The onEdit callback redundantly applies a default (isPublic ?? true) even
though getCategory already guarantees a defined isPublic; update the onEdit prop
to pass isPublic through directly (e.g., onEdit={(id, name, isPublic) =>
openEdit(id, name, isPublic)}) or remove the nullish-coalescing in that lambda
so openEdit receives the original value; locate the onEdit usage in Sidebar.tsx
and change the lambda accordingly, referencing getCategory and openEdit.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/client/src/shared/components/sidebar/OptionsMenuPortal.tsx`:
- Around line 33-47: The code currently leaves name as an empty string when
neither getCategory nor getCategoryName is provided, causing onEdit/onDelete to
receive empty values; update the logic in the block that reads
getCategory/getCategoryName (the section that sets id, name, isPublic) to
perform an early return (e.g., return null) if both getCategory and
getCategoryName are undefined so you never render or call onEdit/onDelete with
empty name/id; ensure this check happens before any use of name/id/isPublic and
references the existing identifiers getCategory, getCategoryName, id, name,
isPublic, onEdit and onDelete.

---

Nitpick comments:
In `@apps/client/src/shared/components/sidebar/Sidebar.tsx`:
- Line 121: The code shadows the outer variable c in the expression
categories?.categories.find((c) => c.id === id) ?? null;—rename the find
callback parameter to a distinct name (e.g., category or cat) to avoid shadowing
and improve readability; update the expression to use
categories?.categories.find((category) => category.id === id) ?? null so the
outer variable and callback param are unambiguous (referencing the find call on
categories.categories in Sidebar.tsx).
- Around line 207-210: The onEdit callback redundantly applies a default
(isPublic ?? true) even though getCategory already guarantees a defined
isPublic; update the onEdit prop to pass isPublic through directly (e.g.,
onEdit={(id, name, isPublic) => openEdit(id, name, isPublic)}) or remove the
nullish-coalescing in that lambda so openEdit receives the original value;
locate the onEdit usage in Sidebar.tsx and change the lambda accordingly,
referencing getCategory and openEdit.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 41db846 and 218095a.

📒 Files selected for processing (2)
  • apps/client/src/shared/components/sidebar/OptionsMenuPortal.tsx
  • apps/client/src/shared/components/sidebar/Sidebar.tsx

Comment on lines 33 to 47
let id: number | null = categoryId;
let name = '';
let isPublic = false;

if (getCategory) {
const category = getCategory(categoryId);

if (!category) return null;

id = category.id;
name = category.name;
isPublic = category.isPublic;
} else if (getCategoryName) {
name = getCategoryName(categoryId);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

getCategorygetCategoryName 둘 다 없는 경우 처리가 누락되었습니다.

현재 로직에서 getCategorygetCategoryName도 제공되지 않으면 name이 빈 문자열로 남게 됩니다. 이 경우 onEditonDelete에 빈 문자열이 전달됩니다.

🛡️ 두 prop 모두 없는 경우 early return 추가 제안
   if (getCategory) {
     const category = getCategory(categoryId);

     if (!category) return null;

     id = category.id;
     name = category.name;
     isPublic = category.isPublic;
   } else if (getCategoryName) {
     name = getCategoryName(categoryId);
+  } else {
+    return null;
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/client/src/shared/components/sidebar/OptionsMenuPortal.tsx` around lines
33 - 47, The code currently leaves name as an empty string when neither
getCategory nor getCategoryName is provided, causing onEdit/onDelete to receive
empty values; update the logic in the block that reads
getCategory/getCategoryName (the section that sets id, name, isPublic) to
perform an early return (e.g., return null) if both getCategory and
getCategoryName are undefined so you never render or call onEdit/onDelete with
empty name/id; ensure this check happens before any use of name/id/isPublic and
references the existing identifiers getCategory, getCategoryName, id, name,
isPublic, onEdit and onDelete.

@constantly-dev
Copy link
Member

  • 진짜.. 롤백을 몇번했는데 체크박스가 api 연결은 되는데 수정 팝업 불러올때 반영되어서 안들어오네요..

이건 서버 수정 반영되는대로 바로 바꿔주세요!

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
apps/extension/src/apis/axios.ts (1)

30-37: 동일 인터페이스 중복 선언은 하나로 정리하는 편이 안전합니다.

현재 같은 이름의 postCategoriesRequest가 두 번 선언되어 타입 의도 추적이 어렵습니다.

♻️ 제안 정리안
-export interface postCategoriesRequest {
-  categoryName: string;
-}
-
 export interface postCategoriesRequest {
   categoryName: string;
   isPublic: boolean;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/extension/src/apis/axios.ts` around lines 30 - 37, The file declares the
same interface name postCategoriesRequest twice which creates ambiguity; remove
the duplicate and merge the properties into a single exported interface named
postCategoriesRequest that includes both categoryName: string and isPublic:
boolean, replace the two declarations with one consolidated declaration (and
update any imports/usages if necessary) so the type is uniquely defined and
exported from apps/extension/src/apis/axios.ts.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/client/src/shared/components/sidebar/Sidebar.tsx`:
- Around line 120-124: The getCategory helper (and the other occurrence using (c
as any).isPublic ?? true) wrongly defaults missing isPublic to true; change
these to default to false instead—locate getCategory and the other mapping that
sets isPublic, remove the "?? true" behavior and replace with an explicit
boolean coercion or conditional that yields false when isPublic is
null/undefined (e.g., use (typeof (c as any).isPublic === 'boolean' ? (c as
any).isPublic : false) or !!(c as any).isPublic) so undefined values do not
become public.

In `@apps/extension/src/apis/axios.ts`:
- Around line 40-43: The API helper that posts to '/api/v3/categories' currently
returns response.data (inner payload) which breaks callers expecting the full
response shape (e.g., useCategoryManager accessing res.data.categoryId); change
the return to preserve the original response object (return response) or wrap
the payload back into the same contract (e.g., return { data: response.data, ...
} ) so that callers like useCategoryManager can continue to access
res.data.categoryId; locate the post call using
apiRequest.post('/api/v3/categories') and update its return accordingly.

---

Nitpick comments:
In `@apps/extension/src/apis/axios.ts`:
- Around line 30-37: The file declares the same interface name
postCategoriesRequest twice which creates ambiguity; remove the duplicate and
merge the properties into a single exported interface named
postCategoriesRequest that includes both categoryName: string and isPublic:
boolean, replace the two declarations with one consolidated declaration (and
update any imports/usages if necessary) so the type is uniquely defined and
exported from apps/extension/src/apis/axios.ts.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 218095a and 3b5607a.

📒 Files selected for processing (8)
  • apps/client/src/shared/apis/axios.ts
  • apps/client/src/shared/apis/queries.ts
  • apps/client/src/shared/components/sidebar/Sidebar.tsx
  • apps/client/src/shared/types/api.ts
  • apps/extension/src/apis/axios.ts
  • apps/extension/src/hooks/useCategoryManager.ts
  • apps/extension/src/pages/MainPop.tsx
  • packages/design-system/src/components/popup/PopupContainer.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/client/src/shared/types/api.ts

Comment on lines 120 to 124
const getCategory = (id: number | null) => {
const c = categories?.categories.find((c) => c.id === id) ?? null;
if (!c) return null;
return { id: c.id, name: c.name, isPublic: (c as any).isPublic ?? true };
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

isPublic 기본값을 true로 강제하면 의도치 않은 공개 전환 위험이 있습니다.

Line 123, Line 208-210의 ?? true 때문에 값이 비어 있는 순간에도 공개로 전파될 수 있습니다. 최소한 true 강제는 제거하고 안전한 기본값(예: false)으로 두는 편이 좋습니다.

🔒 제안 수정안
   const getCategory = (id: number | null) => {
-    const c = categories?.categories.find((c) => c.id === id) ?? null;
+    const c = categories?.categories.find((category) => category.id === id);
     if (!c) return null;
-    return { id: c.id, name: c.name, isPublic: (c as any).isPublic ?? true };
+    return { id: c.id, name: c.name, isPublic: c.isPublic ?? false };
   };
@@
-            onEdit={(id, name, isPublic) =>
-              openEdit(id, name, isPublic ?? true)
-            }
+            onEdit={(id, name, isPublic) => openEdit(id, name, isPublic)}

Also applies to: 208-210

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/client/src/shared/components/sidebar/Sidebar.tsx` around lines 120 -
124, The getCategory helper (and the other occurrence using (c as any).isPublic
?? true) wrongly defaults missing isPublic to true; change these to default to
false instead—locate getCategory and the other mapping that sets isPublic,
remove the "?? true" behavior and replace with an explicit boolean coercion or
conditional that yields false when isPublic is null/undefined (e.g., use (typeof
(c as any).isPublic === 'boolean' ? (c as any).isPublic : false) or !!(c as
any).isPublic) so undefined values do not become public.

Comment on lines +40 to 43
const { data: response } = await apiRequest.post('/api/v3/categories', data);

return response.data;
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

응답 반환 형태 변경으로 카테고리 생성 후 처리 흐름이 깨집니다.

Line 40-42에서 현재 response.data(내부 data)만 반환하고 있어, useCategoryManagerres.data.categoryId 접근이 깨집니다. 기존 계약(상위 응답 객체 반환)을 유지하거나 소비 코드를 함께 수정해야 합니다.

🔧 제안 수정안
 export const postCategories = async (data: postCategoriesRequest) => {
-  const { data: response } = await apiRequest.post('/api/v3/categories', data);
-
-  return response.data;
+  const response = await apiRequest.post('/api/v3/categories', data);
+  return response.data;
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { data: response } = await apiRequest.post('/api/v3/categories', data);
return response.data;
};
export const postCategories = async (data: postCategoriesRequest) => {
const response = await apiRequest.post('/api/v3/categories', data);
return response.data;
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/extension/src/apis/axios.ts` around lines 40 - 43, The API helper that
posts to '/api/v3/categories' currently returns response.data (inner payload)
which breaks callers expecting the full response shape (e.g., useCategoryManager
accessing res.data.categoryId); change the return to preserve the original
response object (return response) or wrap the payload back into the same
contract (e.g., return { data: response.data, ... } ) so that callers like
useCategoryManager can continue to access res.data.categoryId; locate the post
call using apiRequest.post('/api/v3/categories') and update its return
accordingly.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
apps/client/src/shared/apis/queries.ts (1)

222-229: GET 요청에 useMutation 사용은 의미적으로 부적절합니다.

getCategoryDetail은 데이터를 조회하는 GET 요청이므로 useQuery를 사용하는 것이 React Query의 권장 패턴입니다. useMutation은 부수 효과(side-effect)가 있는 작업(POST/PUT/PATCH/DELETE)에 사용해야 합니다.

현재 구현도 동작하지만, 캐싱, 자동 리페치, stale 데이터 관리 등 useQuery의 이점을 활용할 수 없습니다.

♻️ useQuery로 변경 제안
-export const useGetCategoryDetail = (): UseMutationResult<
-  CategoryDetailResponse,
-  AxiosError,
-  number
-> => {
-  return useMutation({
-    mutationFn: (categoryId: number) => getCategoryDetail(categoryId),
-  });
-};
+export const useGetCategoryDetail = (categoryId: number | null) => {
+  return useQuery({
+    queryKey: ['categoryDetail', categoryId],
+    queryFn: () => getCategoryDetail(categoryId!),
+    enabled: categoryId !== null,
+  });
+};

참고: 현재 PR 노트에서 서버 수정이 반영되면 변경이 필요하다고 언급되어 있으므로, 이 리팩토링은 서버 수정과 함께 진행하는 것을 권장합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/client/src/shared/apis/queries.ts` around lines 222 - 229,
useGetCategoryDetail currently uses useMutation for a GET request; change it to
useQuery so React Query can cache and manage stale state. Replace the
useMutation-based implementation in useGetCategoryDetail with a useQuery that
accepts a categoryId param (or takes it via closure), uses the query key
['categoryDetail', categoryId], sets queryFn to call
getCategoryDetail(categoryId), returns a UseQueryResult<CategoryDetailResponse,
AxiosError>, and enable the query only when categoryId is valid (e.g., enabled:
!!categoryId) so it doesn't run unintentionally.
apps/client/src/shared/components/sidebar/hooks/useCategoryActions.ts (1)

32-33: useCategoryActions에서 반환되지만 사용되지 않는 코드 제거하기

Sidebar.tsx에서 useGetCategoryDetail을 직접 호출하고 있어, useCategoryActions 훅에서 반환하는 categoryDetailhandleOpenEditCategory는 실제로 사용되지 않습니다. 이 훅의 반환값에서 불필요한 항목들을 제거하거나, 카테고리 상세 조회 로직을 한 곳에서만 관리하도록 통합하는 것을 권장합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/client/src/shared/components/sidebar/hooks/useCategoryActions.ts` around
lines 32 - 33, The hook useCategoryActions currently calls useGetCategoryDetail
and returns categoryDetail and handleOpenEditCategory which are unused because
Sidebar.tsx calls useGetCategoryDetail directly; remove the redundant call and
unused return values from useCategoryActions (delete the const { mutate:
getCategoryDetail, data: categoryDetail } = useGetCategoryDetail() line and stop
returning categoryDetail and handleOpenEditCategory), or alternatively move the
detail-fetching logic into useCategoryActions and update Sidebar.tsx to use the
hook exclusively—adjust whichever file (useCategoryActions or Sidebar.tsx) so
only one place manages useGetCategoryDetail and eliminate the unused symbols to
keep the API minimal.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/client/src/shared/components/sidebar/Sidebar.tsx`:
- Around line 38-39: Remove the unused destructured variable to fix the TS6133
build error: update the call to useGetCategoryDetail so it only extracts the
used mutate function (e.g., keep "mutate: getCategoryDetail" and drop "data:
categoryDetail"), locating this change where useGetCategoryDetail is invoked in
Sidebar.tsx; ensure no other references to categoryDetail remain before
committing.

---

Nitpick comments:
In `@apps/client/src/shared/apis/queries.ts`:
- Around line 222-229: useGetCategoryDetail currently uses useMutation for a GET
request; change it to useQuery so React Query can cache and manage stale state.
Replace the useMutation-based implementation in useGetCategoryDetail with a
useQuery that accepts a categoryId param (or takes it via closure), uses the
query key ['categoryDetail', categoryId], sets queryFn to call
getCategoryDetail(categoryId), returns a UseQueryResult<CategoryDetailResponse,
AxiosError>, and enable the query only when categoryId is valid (e.g., enabled:
!!categoryId) so it doesn't run unintentionally.

In `@apps/client/src/shared/components/sidebar/hooks/useCategoryActions.ts`:
- Around line 32-33: The hook useCategoryActions currently calls
useGetCategoryDetail and returns categoryDetail and handleOpenEditCategory which
are unused because Sidebar.tsx calls useGetCategoryDetail directly; remove the
redundant call and unused return values from useCategoryActions (delete the
const { mutate: getCategoryDetail, data: categoryDetail } =
useGetCategoryDetail() line and stop returning categoryDetail and
handleOpenEditCategory), or alternatively move the detail-fetching logic into
useCategoryActions and update Sidebar.tsx to use the hook exclusively—adjust
whichever file (useCategoryActions or Sidebar.tsx) so only one place manages
useGetCategoryDetail and eliminate the unused symbols to keep the API minimal.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3b5607a and 894a4ea.

📒 Files selected for processing (5)
  • apps/client/src/shared/apis/axios.ts
  • apps/client/src/shared/apis/queries.ts
  • apps/client/src/shared/components/sidebar/Sidebar.tsx
  • apps/client/src/shared/components/sidebar/hooks/useCategoryActions.ts
  • apps/client/src/shared/types/api.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/client/src/shared/types/api.ts

Comment on lines 38 to 39
const { mutate: getCategoryDetail, data: categoryDetail } =
useGetCategoryDetail();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

categoryDetail이 선언되었지만 사용되지 않아 빌드가 실패합니다.

파이프라인 오류에서 TS6133: 'categoryDetail' is declared but its value is never read.가 보고되었습니다. 사용하지 않는 변수는 제거해야 합니다.

🔧 수정 제안
-  const { mutate: getCategoryDetail, data: categoryDetail } =
-    useGetCategoryDetail();
+  const { mutate: getCategoryDetail } = useGetCategoryDetail();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { mutate: getCategoryDetail, data: categoryDetail } =
useGetCategoryDetail();
const { mutate: getCategoryDetail } = useGetCategoryDetail();
🧰 Tools
🪛 GitHub Actions: ci

[error] 38-38: TS6133: 'categoryDetail' is declared but its value is never read.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/client/src/shared/components/sidebar/Sidebar.tsx` around lines 38 - 39,
Remove the unused destructured variable to fix the TS6133 build error: update
the call to useGetCategoryDetail so it only extracts the used mutate function
(e.g., keep "mutate: getCategoryDetail" and drop "data: categoryDetail"),
locating this change where useGetCategoryDetail is invoked in Sidebar.tsx;
ensure no other references to categoryDetail remain before committing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat 기능 개발하라 개발 달려라 달려

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] 모달 수정 + 익스텐션 라이팅 수정

2 participants